home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / alpha.arc / TELNET.C < prev    next >
C/C++ Source or Header  |  1988-02-16  |  10KB  |  477 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "timer.h"
  5. #include "icmp.h"
  6. #include "netuser.h"
  7. #include "tcp.h"
  8. #include "telnet.h"
  9. #include "session.h"
  10.  
  11. #define    CTLZ    26
  12.  
  13. extern char nospace[];
  14. extern char badhost[];
  15. int refuse_echo = 0;
  16. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  17.  
  18. #ifdef    DEBUG
  19. char *t_options[] = {
  20.     "Transmit Binary",
  21.     "Echo",
  22.     "",
  23.     "Suppress Go Ahead",
  24.     "",
  25.     "Status",
  26.     "Timing Mark"
  27. };
  28. #endif
  29.  
  30. /* Execute user telnet command */
  31. int
  32. dotelnet(argc,argv)
  33. int argc;
  34. char *argv[];
  35. {
  36.     void t_state(),rcv_char(),tn_tx();
  37.     char *inet_ntoa();
  38.     int32 resolve();
  39.     int send_tel();
  40.         int unix_send_tel();
  41.     struct session *s;
  42.     struct telnet *tn;
  43.     struct tcb *tcb;
  44.     struct socket lsocket,fsocket;
  45.  
  46.  
  47.     lsocket.address = ip_addr;
  48.     lsocket.port = lport++;
  49.     if((fsocket.address = resolve(argv[1])) == 0){
  50.         printf(badhost,argv[1]);
  51.         return 1;
  52.     }
  53.     if(argc < 3)
  54.         fsocket.port = TELNET_PORT;
  55.     else
  56.         fsocket.port = atoi(argv[2]);
  57.  
  58.     /* Allocate a session descriptor */
  59.     if((s = newsession()) == NULLSESSION){
  60.         printf("Too many sessions\n");
  61.         return 1;
  62.     }
  63.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  64.         strcpy(s->name,argv[1]);
  65.     s->type = TELNET;
  66.     if ((refuse_echo == 0) && (unix_line_mode != 0)) {
  67.         s->parse = unix_send_tel;
  68.     } else {
  69.         s->parse = send_tel;
  70.     }
  71.     current = s;
  72.  
  73.     /* Create and initialize a Telnet protocol descriptor */
  74.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  75.         printf(nospace);
  76.         s->type = FREE;
  77.         return 1;
  78.     }
  79.     tn->session = s;    /* Upward pointer */
  80.     tn->state = TS_DATA;
  81.     s->cb.telnet = tn;    /* Downward pointer */
  82.  
  83.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  84.      rcv_char,tn_tx,t_state,0,(char *)tn);
  85.  
  86.     tn->tcb = tcb;    /* Downward pointer */
  87.     go();
  88.     return 0;
  89. }
  90.  
  91. /* Process typed characters */
  92. int
  93. unix_send_tel(buf,n)
  94. char *buf;
  95. int16 n;
  96. {
  97.     int i;
  98.  
  99.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  100.         ;
  101.     if (buf[i] == '\r') {
  102.         buf[i] = '\n';
  103.         n = i+1;
  104.     }
  105.     send_tel(buf,n);
  106. }
  107. int
  108. send_tel(buf,n)
  109. char *buf;
  110. int16 n;
  111. {
  112.     struct mbuf *bp,*qdata();
  113.     if(current == NULLSESSION || current->cb.telnet == NULLTN
  114.      || current->cb.telnet->tcb == NULLTCB)
  115.         return;
  116.     /* If we're doing our own echoing and recording is enabled, record it */
  117.     if(!current->cb.telnet->remote[TN_ECHO] && current->record != NULLFILE)
  118.         fwrite(buf,1,n,current->record);
  119.     bp = qdata(buf,n);
  120.     send_tcp(current->cb.telnet->tcb,bp);
  121. }
  122.  
  123. /* Process incoming TELNET characters */
  124. int
  125. tel_input(tn,bp)
  126. register struct telnet *tn;
  127. struct mbuf *bp;
  128. {
  129.     char c;
  130.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  131.     FILE *record;
  132.     char *memchr();
  133.  
  134.     /* Optimization for very common special case -- no special chars */
  135.     if(tn->state == TS_DATA){
  136.         while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) == NULLCHAR){
  137.             if((record = tn->session->record) != NULLFILE)
  138.                 fwrite(bp->data,1,bp->cnt,record);
  139.             while(bp->cnt-- != 0)
  140.                 putchar(*bp->data++);
  141.             bp = free_mbuf(bp);
  142.         }
  143.     }
  144.     while(pullup(&bp,&c,1) == 1){
  145.         switch(tn->state){
  146.         case TS_DATA:
  147.             if(uchar(c) == IAC){
  148.                 tn->state = TS_IAC;
  149.             } else {
  150.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  151.                     c &= 0x7f;
  152.                 putchar(c);
  153.                 if((record = tn->session->record) != NULLFILE)
  154.                     putc(c,record);
  155.             }
  156.             break;
  157.         case TS_IAC:
  158.             switch(uchar(c)){
  159.             case WILL:
  160.                 tn->state = TS_WILL;
  161.                 break;
  162.             case WONT:
  163.                 tn->state = TS_WONT;
  164.                 break;
  165.             case DO:
  166.                 tn->state = TS_DO;
  167.                 break;
  168.             case DONT:
  169.                 tn->state = TS_DONT;
  170.                 break;
  171.             case IAC:
  172.                 putchar(c);
  173.                 tn->state = TS_DATA;
  174.                 break;
  175.             default:
  176.                 tn->state = TS_DATA;
  177.                 break;
  178.             }
  179.             break;
  180.         case TS_WILL:
  181.             willopt(tn,c);
  182.             tn->state = TS_DATA;
  183.             break;
  184.         case TS_WONT:
  185.             wontopt(tn,c);
  186.             tn->state = TS_DATA;
  187.             break;
  188.         case TS_DO:
  189.             doopt(tn,c);
  190.             tn->state = TS_DATA;
  191.             break;
  192.         case TS_DONT:
  193.             dontopt(tn,c);
  194.             tn->state = TS_DATA;
  195.             break;
  196.         }
  197.     }
  198. }
  199.  
  200. /* Telnet receiver upcall routine */
  201. void
  202. rcv_char(tcb,cnt)
  203. register struct tcb *tcb;
  204. int16 cnt;
  205. {
  206.     struct mbuf *bp;
  207.     struct telnet *tn;
  208.     FILE *record;
  209.  
  210.     if((tn = (struct telnet *)tcb->user) == NULLTN){
  211.         /* Unknown connection; ignore it */
  212.         return;
  213.     }
  214.     /* Hold output if we're not the current session */
  215.     if(mode != CONV_MODE || current == NULLSESSION
  216.      || current->type != TELNET || current->cb.telnet != tn)
  217.         return;
  218.  
  219.     if(recv_tcp(tcb,&bp,cnt) > 0)
  220.         tel_input(tn,bp);
  221.  
  222.     fflush(stdout);
  223.     if((record = tn->session->record) != NULLFILE)
  224.         fflush(record);
  225. }
  226. /* Handle transmit upcalls. Used only for file uploading */
  227. void
  228. tn_tx(tcb,cnt)
  229. struct tcb *tcb;
  230. int16 cnt;
  231. {
  232.     struct telnet *tn;
  233.     struct session *s;
  234.     struct mbuf *bp;
  235.     int size;
  236.  
  237.     if((tn = (struct telnet *)tcb->user) == NULLTN
  238.      || (s = tn->session) == NULLSESSION
  239.      || s->upload == NULLFILE)
  240.         return;
  241.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  242.         return;
  243.     if((size = fread(bp->data,1,cnt,s->upload)) > 0){
  244.         bp->cnt = (int16)size;
  245.         send_tcp(tcb,bp);
  246.     } else {
  247.         free_p(bp);
  248.     }
  249.     if(size != cnt){
  250.         /* Error or end-of-file */
  251.         fclose(s->upload);
  252.         s->upload = NULLFILE;
  253.         free(s->ufile);
  254.         s->ufile = NULLCHAR;
  255.     }
  256. }
  257.  
  258. /* State change upcall routine */
  259. void
  260. t_state(tcb,old,new)
  261. register struct tcb *tcb;
  262. char old,new;
  263. {
  264.     struct telnet *tn;
  265.     char notify = 0;
  266.     extern char *tcpstates[];
  267.     extern char *reasons[];
  268.     extern char *unreach[];
  269.     extern char *exceed[];
  270.  
  271.     /* Can't add a check for unknown connection here, it would loop
  272.      * on a close upcall! We're just careful later on.
  273.      */
  274.     tn = (struct telnet *)tcb->user;
  275.  
  276.     if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
  277.         notify = 1;
  278.  
  279.     switch(new){
  280.     case CLOSE_WAIT:
  281.         if(notify)
  282.             printf("%s\n",tcpstates[new]);
  283.         close_tcp(tcb);
  284.         break;
  285.     case CLOSED:    /* court adjourned */
  286.         if(notify){
  287.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  288.             if(tcb->reason == NETWORK){
  289.                 switch(tcb->type){
  290.                 case DEST_UNREACH:
  291.                     printf(": %s unreachable",unreach[tcb->code]);
  292.                     break;
  293.                 case TIME_EXCEED:
  294.                     printf(": %s time exceeded",exceed[tcb->code]);
  295.                     break;
  296.                 }
  297.             }
  298.             printf(")\n");
  299.             cmdmode();
  300.         }
  301.         del_tcp(tcb);
  302.         if(tn != NULLTN)
  303.             free_telnet(tn);
  304.         break;
  305.     default:
  306.         if(notify)
  307.             printf("%s\n",tcpstates[new]);
  308.         break;
  309.     }
  310.     fflush(stdout);
  311. }
  312. /* Delete telnet structure */
  313. static
  314. free_telnet(tn)
  315. struct telnet *tn;
  316. {
  317.     if(tn->session != NULLSESSION)
  318.         freesession(tn->session);
  319.  
  320.     if(tn != NULLTN)
  321.         free((char *)tn);
  322. }
  323.  
  324. /* The guts of the actual Telnet protocol: negotiating options */
  325. static
  326. void
  327. willopt(tn,opt)
  328. struct telnet *tn;
  329. char opt;
  330. {
  331.     int ack;
  332.     void answer();
  333.  
  334. #ifdef    DEBUG
  335.     printf("recv: will ");
  336.     if(uchar(opt) <= NOPTIONS)
  337.         printf("%s\n",t_options[opt]);
  338.     else
  339.         printf("%u\n",opt);
  340. #endif
  341.     
  342.     switch(uchar(opt)){
  343.     case TN_TRANSMIT_BINARY:
  344.     case TN_ECHO:
  345.     case TN_SUPPRESS_GA:
  346.         if(tn->remote[uchar(opt)] == 1)
  347.             return;        /* Already set, ignore to prevent loop */
  348.         if(uchar(opt) == TN_ECHO){
  349.             if(refuse_echo){
  350.                 /* User doesn't want to accept */
  351.                 ack = DONT;
  352.                 break;
  353.             } else
  354.                 raw();        /* Put tty into raw mode */
  355.         }
  356.         tn->remote[uchar(opt)] = 1;
  357.         ack = DO;            
  358.         break;
  359.     default:
  360.         ack = DONT;    /* We don't know what he's offering; refuse */
  361.     }
  362.     answer(tn,ack,opt);
  363. }
  364. static
  365. void
  366. wontopt(tn,opt)
  367. struct telnet *tn;
  368. char opt;
  369. {
  370.     void answer();
  371.  
  372. #ifdef    DEBUG
  373.     printf("recv: wont ");
  374.     if(uchar(opt) <= NOPTIONS)
  375.         printf("%s\n",t_options[uchar(opt)]);
  376.     else
  377.         printf("%u\n",uchar(opt));
  378. #endif
  379.     if(uchar(opt) <= NOPTIONS){
  380.         if(tn->remote[uchar(opt)] == 0)
  381.             return;        /* Already clear, ignore to prevent loop */
  382.         tn->remote[uchar(opt)] = 0;
  383.         if(uchar(opt) == TN_ECHO)
  384.             cooked();    /* Put tty into cooked mode */
  385.     }
  386.     answer(tn,DONT,opt);    /* Must always accept */
  387. }
  388. static
  389. void
  390. doopt(tn,opt)
  391. struct telnet *tn;
  392. char opt;
  393. {
  394.     void answer();
  395.     int ack;
  396.  
  397. #ifdef    DEBUG
  398.     printf("recv: do ");
  399.     if(uchar(opt) <= NOPTIONS)
  400.         printf("%s\n",t_options[uchar(opt)]);
  401.     else
  402.         printf("%u\n",uchar(opt));
  403. #endif
  404.     switch(uchar(opt)){
  405. #ifdef    FUTURE    /* Use when local options are implemented */
  406.         if(tn->local[uchar(opt)] == 1)
  407.             return;        /* Already set, ignore to prevent loop */
  408.         tn->local[uchar(opt)] = 1;
  409.         ack = WILL;
  410.         break;
  411. #endif
  412.     default:
  413.         ack = WONT;    /* Don't know what it is */
  414.     }
  415.     answer(tn,ack,opt);
  416. }
  417. static
  418. void
  419. dontopt(tn,opt)
  420. struct telnet *tn;
  421. char opt;
  422. {
  423.     void answer();
  424.  
  425. #ifdef    DEBUG
  426.     printf("recv: dont ");
  427.     if(uchar(opt) <= NOPTIONS)
  428.         printf("%s\n",t_options[uchar(opt)]);
  429.     else
  430.         printf("%u\n",uchar(opt));
  431. #endif
  432.     if(uchar(opt) <= NOPTIONS){
  433.         if(tn->local[uchar(opt)] == 0){
  434.             /* Already clear, ignore to prevent loop */
  435.             return;
  436.         }
  437.         tn->local[uchar(opt)] = 0;
  438.     }
  439.     answer(tn,WONT,opt);
  440. }
  441. static
  442. void
  443. answer(tn,r1,r2)
  444. struct telnet *tn;
  445. int r1,r2;
  446. {
  447.     struct mbuf *bp,*qdata();
  448.     char s[3];
  449.  
  450. #ifdef    DEBUG
  451.     switch(r1){
  452.     case WILL:
  453.         printf("sent: will ");
  454.         break;
  455.     case WONT:
  456.         printf("sent: wont ");
  457.         break;
  458.     case DO:
  459.         printf("sent: do ");
  460.         break;
  461.     case DONT:
  462.         printf("sent: dont ");
  463.         break;
  464.     }
  465.     if(r2 <= 6)
  466.         printf("%s\n",t_options[r2]);
  467.     else
  468.         printf("%u\n",r2);
  469. #endif
  470.  
  471.     s[0] = IAC;
  472.     s[1] = r1;
  473.     s[2] = r2;
  474.     bp = qdata(s,(int16)3);
  475.     send_tcp(tn->tcb,bp);
  476. }
  477.